package controllers

import (
	"gin/config"
	"gin/models"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
)

type PlayController struct{}

func (c *PlayController) ListPlay(ctx *gin.Context) {
	openID := ctx.GetHeader("X-WX-OPENID")
	user := getUser(openID, ctx)
	if user.ID == 0 {
		return
	}

	page, _ := strconv.Atoi(ctx.Param("page"))
	pageSize := 20

	offset := (page - 1) * pageSize

	var players []models.Players
	config.DB.Where("user_id = ?", user.ID).Order("join_time DESC").Limit(pageSize).Offset(offset).Find(&players)

	var gameIds []uint
	for _, player := range players {
		gameIds = append(gameIds, player.GameID)
	}

	var games []models.Games
	config.DB.Where("id IN ?", gameIds).Find(&games)
	gameMap := make(map[uint]models.Games)
	for _, game := range games {
		gameMap[game.ID] = game
	}

	type GameInfo struct {
		ID           uint      `gorm:"primary_key"`
		Title        string    `json:"title"`
		GameName     string    `json:"game_name"`
		CreateUserId uint      `json:"user_id"`
		IsFinished   bool      `json:"is_finished"`
		PlayerCount  int       `json:"player_count"`
		PicUrl       string    `json:"pic_url"`
		CreatedAt    time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP"`
		Ranking      int8      `json:"ranking"`
		IsChampion   bool      `json:"is_champion"`
	}

	var gameList []GameInfo = []GameInfo{}
	for _, player := range players {
		var gameInfo GameInfo
		gameInfo.Ranking = player.Ranking
		gameInfo.IsChampion = player.IsChampion

		gameId := player.GameID
		gameInfo.ID = gameMap[gameId].ID
		gameInfo.Title = gameMap[gameId].Title
		gameInfo.GameName = gameMap[gameId].GameName
		gameInfo.CreateUserId = gameMap[gameId].CreateUserId
		gameInfo.IsFinished = gameMap[gameId].IsFinished
		gameInfo.PlayerCount = gameMap[gameId].PlayerCount
		gameInfo.PicUrl = gameMap[gameId].PicUrl
		gameInfo.CreatedAt = gameMap[gameId].CreatedAt

		gameList = append(gameList, gameInfo)
	}

	ctx.JSON(http.StatusOK, gameList)
}

func (c *PlayController) CreatePlayer(ctx *gin.Context) {
	openID := ctx.GetHeader("X-WX-OPENID")
	user := getUser(openID, ctx)
	if user.ID == 0 {
		return
	}

	gameId, _ := strconv.Atoi(ctx.Param("gameId"))
	game := getGame(gameId, ctx)
	if game.IsFinished {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": 0,
			"msg":  "game is finished",
			"game": game,
		})
		return
	}

	if game.CreateUserId != user.ID {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": 0,
			"msg":  "only game creator can add player",
			"game": game,
		})
		return
	}

	var oldPlayers []models.Players
	config.DB.Where("game_id = ?", game.ID).Find(&oldPlayers)
	var oldIds []uint
	for _, room := range oldPlayers {
		oldIds = append(oldIds, room.ID)
	}

	var players []models.Players
	if err := ctx.ShouldBindJSON(&players); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	for i := range players {
		players[i].GameID = game.ID
	}

	if err := config.DB.Create(&players).Error; err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create game players"})
		return
	} else {
		config.DB.Delete(&oldPlayers, oldIds)
		game.PlayerCount = len(players)
		config.DB.Save(&game)
	}

	ctx.JSON(http.StatusOK, players)
}

func (c *PlayController) JoinGame(ctx *gin.Context) {

	openID := ctx.GetHeader("X-WX-OPENID")
	user := getUser(openID, ctx)
	if user.ID == 0 {
		return
	}

	gameId, _ := strconv.Atoi(ctx.Param("gameId"))
	game := getGame(gameId, ctx)
	if game.IsFinished {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": 0,
			"msg":  "game is finished",
			"game": game,
		})
		return
	}

	type PlayerRequest struct {
		PlayerID uint   `json:"player_id" binding:"required"`
		Color    string `json:"color"`
		Score    uint   `json:"score"`
	}
	var req PlayerRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	var player models.Players
	playerID := req.PlayerID
	if config.DB.Where("game_id = ? AND id = ?", game.ID, playerID).First(&player).Error != nil { // 查询游戏
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code":    0,
			"msg":     "玩家ID不存在",
			"play_id": playerID,
			"game_id": game.ID,
		})
	}

	if player.UserID != user.ID && player.UserID != 0 {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code":    0,
			"msg":     "玩家ID不匹配",
			"play_id": playerID,
			"game_id": game.ID,
		})
		return
	}

	player.UserID = user.ID
	player.Color = req.Color
	player.Score = req.Score
	player.JoinTime = time.Now()
	config.DB.Save(&player)

	type PlayerRpo struct {
		Player models.Players
		User   models.User
	}

	var p PlayerRpo
	p.Player = player
	p.User = user

	ctx.JSON(http.StatusOK, p)

}

func getUser(openID string, ctx *gin.Context) models.User {

	var user models.User
	if openID == "" { // 检查是否包含openID
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code":   0,
			"msg":    "openID不能为空",
			"openID": openID,
		})
		return user
	}
	if config.DB.Where("wx_uid = ?", openID).First(&user).Error != nil { // 查询用户
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code":   0,
			"msg":    "用户不存在",
			"openID": openID,
		})
	}
	return user
}

func getGame(gameId int, ctx *gin.Context) models.Games {
	var game models.Games
	if config.DB.Where("id = ?", gameId).First(&game).Error != nil { // 查询游戏
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code":   0,
			"msg":    "游戏不存在",
			"gameId": gameId,
		})
	}
	return game
}
